﻿using System;
using System.Reflection;
using WJP.ManagedProperty;
using WJP.ObjectModel;

namespace WJP.MetaModel
{
    /// <summary>
    /// 属性元数据
    /// </summary>
    public abstract class PropertyMeta : Meta
    {
        private IPropertyRuntime _runtimeProperty;
        private Type _propertyType;

        [UnAutoFreeze]
        private EntityMeta _owner;

        /// <summary>
        /// 如果本元数据对应的实体属性是由托管属性编写的，那么这里返回它所对应的托管属性。
        /// </summary>
        public IManagedProperty ManagedProperty { get; internal set; }

        /// <summary>
        /// 返回这个托管属性对应的 CLR 属性，如果没有对应的 CLR 属性（或者找到多个），则返回 null。
        /// </summary>
        public PropertyInfo CLRProperty
        {
            get
            {
                if (this.Owner == null)
                    return null;
                Type entityType = this._owner.EntityType;
                string name = this.ManagedProperty.Name;
                try
                {
                    return entityType.GetProperty(name, this.ManagedProperty.PropertyType);
                }
                catch
                {
                    return null;
                }
            }
        }

        public override string Name
        {
            get
            {
                return this._runtimeProperty.Name;
            }
            set
            {
                throw new NotSupportedException();
            }
        }

        /// <summary>
        /// 属性的类型。
        /// 这个类型并不一定与托管属性的类型一致。例如 Id 属性，声明的是 object 类型，但是实际可能是 int、string 等。
        /// </summary>
        public Type PropertyType
        {
            get
            {
                return this._propertyType;
            }
            set
            {
                this.SetValue(ref this._propertyType, value, nameof(PropertyType));
            }
        }

        /// <summary>对应的属性</summary>
        public IPropertyRuntime Runtime
        {
            get
            {
                if (this._runtimeProperty == null)
                    throw new ArgumentNullException("_runtimeProperty");
                return this._runtimeProperty;
            }
            set
            {
                this.SetValue(ref this._runtimeProperty, value, nameof(Runtime));
            }
        }

        /// <summary>所在类型的元数据</summary>
        public EntityMeta Owner
        {
            get
            {
                return this._owner;
            }
            set
            {
                this.SetValue(ref this._owner, value, nameof(Owner));
            }
        }
    }
}